package com.vf.framework.aspectj;

import com.google.gson.Gson;
import com.vf.common.annotation.AutoCache;
import com.vf.common.annotation.AutoCleanCache;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
@Slf4j
public class RedisCachingAdvice {

    @Autowired
    private RedisTemplate redisTemplate;


    @Around("@annotation(com.vf.common.annotation.AutoCache)")
    public Object autoCache(ProceedingJoinPoint pjp){
        log.debug("执行通知");
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getName();
        log.debug("被增强的方法：{}", methodName);

        AutoCache annotation = method.getAnnotation(AutoCache.class);
        log.debug("注解：{}",annotation);

        String group = annotation.group();
        log.debug("用户缓存数据使用的组名：{}",group);

        long ttl = annotation.ttl();
        log.debug("用户缓存数据的时效：{}",ttl);

        String key = group + methodName + ":" + Arrays.toString(pjp.getArgs());
        log.debug("用户缓存用的完整的key：{}",key);

        // 如果redis中有这个key
        Gson gson = new Gson();
        if (redisTemplate.hasKey(key)){
            // 查出来直接返回
            log.debug("查缓存");
            Object o = gson.fromJson(
                    redisTemplate.opsForValue().get(key).toString(),
                    method.getReturnType()
            );
            return o;
        }

        log.debug("缓存中没有，正常调用");
        Object res = null;
        try {
            res = pjp.proceed();
            log.debug("原方法调用结果：{}",res);
            String json = gson.toJson(res);
            log.debug("json序列化：{}",json);
            if (ttl > 0){
                redisTemplate.opsForValue().set(key, json, ttl, TimeUnit.MILLISECONDS);
            }else {
                redisTemplate.opsForValue().set(key, json);
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return res;
    }



    @Around("@annotation(com.vf.common.annotation.AutoCleanCache)")
    public Object autoCleanCache(ProceedingJoinPoint pjp){
        log.debug("增删改操作要清除缓存");
        Object res = null;
        try {
            res = pjp.proceed();
            MethodSignature signature = (MethodSignature) pjp.getSignature();
            Method method = signature.getMethod();
            AutoCleanCache annotation = method.getAnnotation(AutoCleanCache.class);
            log.debug("注解：{}",annotation);
            String group = annotation.group();
            log.debug("要清除的数据组：{}",group);

            List<String> keysToDelete = new ArrayList<>();
            ScanOptions scanOptions = ScanOptions.scanOptions().match(group + "*").build();
            try(Cursor<byte[]> cursor = redisTemplate.getConnectionFactory()
                    .getConnection()
                    .scan(scanOptions)){

                while (cursor.hasNext()) {
                    String key = new String(cursor.next());
                    log.debug("通过scan获取的key: {}",key);
                    keysToDelete.add(key);
                }
            }

            if (!keysToDelete.isEmpty()){
                log.debug("批量删除缓存的数据：{}",keysToDelete);
                redisTemplate.delete(keysToDelete);
            }

        } catch (Throwable e) {
            e.printStackTrace();
        }
        return res;
    }
}
